home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / pine3.07 / contrib / port.isc / c-client / os_isc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-12  |  22.1 KB  |  812 lines

  1. /*
  2.  * Program:    Operating-system dependent routines -- PTX version
  3.  *
  4.  * Author:    Donn Cave/Mark Crispin
  5.  *        University Computing Services, JE-30
  6.  *        University of Washington
  7.  *        Seattle, WA 98195
  8.  *        Internet: donn@cac.washington.edu
  9.  *
  10.  * Date:    10 April 1992
  11.  * Last Edited:    14 May 1992
  12.  *
  13.  * Copyright 1992 by the University of Washington
  14.  *
  15.  *  Permission to use, copy, modify, and distribute this software and its
  16.  * documentation for any purpose and without fee is hereby granted, provided
  17.  * that the above copyright notice appears in all copies and that both the
  18.  * above copyright notice and this permission notice appear in supporting
  19.  * documentation, and that the name of the University of Washington not be
  20.  * used in advertising or publicity pertaining to distribution of the software
  21.  * without specific, written prior permission.  This software is made
  22.  * available "as is", and
  23.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  24.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  25.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  26.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  27.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  28.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  29.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  30.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  31.  *
  32.  */
  33.  
  34. /* TCP input buffer */
  35.  
  36. #define BUFLEN 8192
  37.  
  38.  
  39. /* TCP I/O stream (must be before osdep.h is included) */
  40.  
  41. #define TCPSTREAM struct tcp_stream
  42. TCPSTREAM {
  43.   char *host;            /* host name */
  44.   char *localhost;        /* local host name */
  45.   int tcpsi;            /* input socket */
  46.   int tcpso;            /* output socket */
  47.   int ictr;            /* input counter */
  48.   char *iptr;            /* input pointer */
  49.   char ibuf[BUFLEN];        /* input buffer */
  50. };
  51.  
  52.  
  53. #include <ctype.h>
  54. #include <sys/types.h>
  55. #include <sys/time.h>
  56. #include <sys/tiuser.h>
  57. #include <sys/stropts.h>
  58. #include <sys/poll.h>
  59. #include <netinet/in.h>
  60. #include <netdb.h>
  61. #include <ctype.h>
  62. #include <regexpr.h>
  63. #include <errno.h>
  64. #include <pwd.h>
  65. #include <shadow.h>
  66. #include <syslog.h>
  67. #include <sys/file.h>
  68. #include <sys/stat.h>
  69. #include <dirent.h>
  70. #include "osdep.h"
  71. #include "mail.h"
  72. #include "misc.h"
  73.  
  74. extern int sys_nerr;
  75. extern char *sys_errlist[];
  76.  
  77. #define toint(c)    ((c)-'0')
  78. #define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
  79.  
  80. /* Write current time in RFC 822 format
  81.  * Accepts: destination string
  82.  */
  83.  
  84. char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  85. char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  86.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  87.  
  88. void rfc822_date (date)
  89.     char *date;
  90. {
  91.   int zone;
  92.   char *zonename;
  93.   struct tm *t;
  94.   int time_sec;
  95.  
  96.   /*
  97.     In DYNIX/ptx, we don't have gettimeofday() or timezone().
  98.     There are two external variables that interact to provide
  99.     a time zone name:
  100.         extern char *tzname[2] = {normal, daylight}
  101.         extern int daylight = 0 (normally) or 1 (in the summer)
  102.  
  103.     Another external variable
  104.         extern long timezone
  105.     contains the difference in seconds from UTC.
  106.  
  107.     These have to be initialized by running tzset ().  Whether
  108.     they are initialized correctly at that point depends on the
  109.     correctness of the TZ environment variable, which is normally
  110.     set in /etc/TIMEZONEZ.
  111.   */
  112.   time_sec = time (0);
  113.   t = localtime (&time_sec);    /* convert to individual items */
  114.                 /* use this for older systems */
  115.   tzset ();
  116.   zone = (t->tm_isdst ? 60 : 0) - ((daylight == 0 ? timezone : altzone) / 60);
  117.   zonename = tzname[daylight != 0];
  118.                 /* and output it */
  119.   sprintf (date,"%s, %d %s %d %02d:%02d:%02d %+03d%02d (%s)",
  120.        days[t->tm_wday],t->tm_mday,months[t->tm_mon],t->tm_year+1900,
  121.        t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60,zonename);
  122. }
  123.  
  124. /* Get a block of free storage
  125.  * Accepts: size of desired block
  126.  * Returns: free storage block
  127.  */
  128.  
  129. void *fs_get (size)
  130.     size_t size;
  131. {
  132.   void *block = malloc (size);
  133.   if (!block) fatal ("Out of free storage");
  134.   return (block);
  135. }
  136.  
  137.  
  138. /* Resize a block of free storage
  139.  * Accepts: ** pointer to current block
  140.  *        new size
  141.  */
  142.  
  143. void fs_resize (block,size)
  144.     void **block;
  145.     size_t size;
  146. {
  147.   if (!(*block = realloc (*block,size))) fatal ("Can't resize free storage");
  148. }
  149.  
  150.  
  151. /* Return a block of free storage
  152.  * Accepts: ** pointer to free storage block
  153.  */
  154.  
  155. void fs_give (block)
  156.     void **block;
  157. {
  158.   free (*block);
  159.   *block = NIL;
  160. }
  161.  
  162.  
  163. /* Report a fatal error
  164.  * Accepts: string to output
  165.  */
  166.  
  167. void fatal (string)
  168.     char *string;
  169. {
  170.   mm_fatal (string);        /* output the string */
  171.   syslog (LOG_ALERT,"IMAP C-Client crash: %s",string);
  172.   abort ();            /* die horribly */
  173. }
  174.  
  175. /* Copy string with CRLF newlines
  176.  * Accepts: destination string
  177.  *        pointer to size of destination string
  178.  *        source string
  179.  *        length of source string
  180.  */
  181.  
  182. char *strcrlfcpy (dst,dstl,src,srcl)
  183.     char **dst;
  184.     unsigned long *dstl;
  185.     char *src;
  186.     unsigned long srcl;
  187. {
  188.   long i,j;
  189.   char *d = src;
  190.                 /* count number of LF's in source string(s) */
  191.   for (i = srcl,j = 0; j < srcl; j++) if (*d++ == '\012') i++;
  192.   if (i > *dstl) {        /* resize if not enough space */
  193.     fs_give ((void **) dst);    /* fs_resize does an unnecessary copy */
  194.     *dst = (char *) fs_get ((*dstl = i) + 1);
  195.   }
  196.   d = *dst;            /* destination string */
  197.                 /* copy strings, inserting CR's before LF's */
  198.   while (srcl--) switch (*src) {
  199.   case '\015':            /* unlikely carriage return */
  200.     *d++ = *src++;        /* copy it and any succeeding linefeed */
  201.     if (srcl && *src == '\012') {
  202.       *d++ = *src++;
  203.       srcl--;
  204.     }
  205.     break;
  206.   case '\012':            /* line feed? */
  207.     *d++ ='\015';        /* yes, prepend a CR, drop into default case */
  208.   default:            /* ordinary chararacter */
  209.     *d++ = *src++;        /* just copy character */
  210.     break;
  211.   }
  212.   *d = '\0';            /* tie off destination */
  213.   return *dst;            /* return destination */
  214. }
  215.  
  216.  
  217. /* Length of string after strcrlflen applied
  218.  * Accepts: source string
  219.  *        length of source string
  220.  */
  221.  
  222. unsigned long strcrlflen (src,srcl)
  223.     char *src;
  224.     unsigned long srcl;
  225. {
  226.   long i = srcl;        /* look for LF's */
  227.   while (srcl--) switch (*src++) {
  228.   case '\015':            /* unlikely carriage return */
  229.     if (srcl && *src == '\012') { src++; srcl--; }
  230.     break;
  231.   case '\012':            /* line feed? */
  232.     i++;
  233.   default:            /* ordinary chararacter */
  234.     break;
  235.   }
  236.   return i;
  237. }
  238.  
  239. /* Server log in
  240.  * Accepts: user name string
  241.  *        password string
  242.  *        optional place to return home directory
  243.  * Returns: T if password validated, NIL otherwise
  244.  */
  245.  
  246. int server_login (user,pass,home)
  247.     char *user;
  248.     char *pass;
  249.     char **home;
  250. {
  251.   struct passwd *pw = getpwnam (lcase (user));
  252.   struct spwd *sp;
  253.                 /* no entry for this user or root */
  254.   if (!(pw && pw->pw_uid)) return NIL;
  255.                 /* validate password and password aging */
  256.   sp = getspnam (pw->pw_name);
  257.   if (strcmp (sp->sp_pwdp, (char *) crypt (pass,sp->sp_pwdp))) return NIL;
  258.   else if ((sp->sp_lstchg > 0) && (sp->sp_max > 0) &&
  259.        ((sp->sp_lstchg + sp->sp_max) < (time (0) / (60*60*24))))
  260.     return NIL;
  261.   setgid (pw->pw_gid);        /* all OK, login in as that user */
  262.   setuid (pw->pw_uid);
  263.                 /* note home directory */
  264.   if (home) *home = cpystr (pw->pw_dir);
  265.   return T;
  266. }
  267.  
  268. /* TCP/IP open
  269.  * Accepts: host name
  270.  *        contact port number
  271.  * Returns: TCP/IP stream if success else NIL
  272.  */
  273.  
  274. TCPSTREAM *tcp_open (host,port)
  275.     char *host;
  276.     int port;
  277. {
  278.   TCPSTREAM *stream = NIL;
  279.   int sock;
  280.   char *s;
  281.   struct sockaddr_in sin;
  282.   struct hostent *host_name;
  283.   char hostname[MAILTMPLEN];
  284.   char tmp[MAILTMPLEN];
  285.     extern int t_errno;
  286.     extern char *t_errlist[];
  287.     struct t_call *sndcall;
  288.  
  289.   /* The domain literal form is used (rather than simply the dotted decimal
  290.      as with other Unix programs) because it has to be a valid "host name"
  291.      in mailsystem terminology. */
  292.                 /* look like domain literal? */
  293.   if (host[0] == '[' && host[(strlen (host))-1] == ']') {
  294.     strcpy (hostname,host+1);    /* yes, copy number part */
  295.     hostname[(strlen (hostname))-1] = '\0';
  296.     if ((sin.sin_addr.s_addr = inet_addr (hostname)) != -1) {
  297.       sin.sin_family = AF_INET;    /* family is always Internet */
  298.       strcpy (hostname,host);    /* hostname is user's argument */
  299.     }
  300.     else {
  301.       sprintf (tmp,"Bad format domain-literal: %.80s",host);
  302.       mm_log (tmp,ERROR);
  303.       return NIL;
  304.     }
  305.   }
  306.  
  307.   else {            /* lookup host name, note that brain-dead Unix
  308.                    requires lowercase! */
  309.     strcpy (hostname,host);    /* in case host is in write-protected memory */
  310.     if ((host_name = gethostbyname (lcase (hostname)))) {
  311.                 /* copy address type */
  312.       sin.sin_family = host_name->h_addrtype;
  313.                 /* copy host name */
  314.       strcpy (hostname,host_name->h_name);
  315.                 /* copy host addresses */
  316.       memcpy (&sin.sin_addr,host_name->h_addr,host_name->h_length);
  317.     }
  318.     else {
  319.       sprintf (tmp,"No such host as %.80s",host);
  320.       mm_log (tmp,ERROR);
  321.       return NIL;
  322.     }
  323.   }
  324.  
  325.                 /* copy port number in network format */
  326.   if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open");
  327.  
  328.                 /* get a TCP stream */
  329.   t_errno = 0;
  330.   if (((sock = t_open (TLI_TCP, O_RDWR, 0)) < 0) ||
  331.       (t_bind (sock, 0, 0) < 0) ||
  332.       ((sndcall = (struct t_call *) t_alloc (sock, T_CALL, T_ADDR)) == 0))
  333.   {
  334.     sprintf (tmp,"Unable to create TCP socket: %s",t_errlist[t_errno]);
  335.     mm_log (tmp,ERROR);
  336.     return NIL;
  337.   }
  338.                 /* connect to address. */
  339.   sndcall->addr.len = sndcall->addr.maxlen = sizeof (sin);
  340.   sndcall->addr.buf = (char *) &sin;
  341.   sndcall->opt.len = 0;
  342.   sndcall->udata.len = 0;
  343.   if (t_connect (sock, sndcall, 0) < 0) {
  344.     sprintf (tmp,"Can't connect to %.80s,%d: %s",hostname,port,
  345.          t_errlist[t_errno]);
  346.     mm_log (tmp,ERROR);
  347.     return NIL;
  348.   }
  349.                 /* push streams module for read()/write(). */
  350.   if (ioctl (sock, I_PUSH, "tirdwr") < 0) {
  351.     sprintf (tmp,"Unable to create TCP socket: %s",t_errlist[t_errno]);
  352.     mm_log (tmp,ERROR);
  353.     return NIL;
  354.   }
  355.                 /* create TCP/IP stream */
  356.   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  357.                 /* copy official host name */
  358.   stream->host = cpystr (hostname);
  359.                 /* get local name */
  360.   gethostname (tmp,MAILTMPLEN-1);
  361.   stream->localhost = cpystr ((host_name = gethostbyname (tmp)) ?
  362.                   host_name->h_name : tmp);
  363.                 /* init sockets */
  364.   stream->tcpsi = stream->tcpso = sock;
  365.   stream->ictr = 0;        /* init input counter */
  366.   return stream;        /* return success */
  367. }
  368.  
  369. /* TCP/IP authenticated open
  370.  * Accepts: host name
  371.  *        service name
  372.  * Returns: TCP/IP stream if success else NIL
  373.  */
  374.  
  375. TCPSTREAM *tcp_aopen (host,service)
  376.     char *host;
  377.     char *service;
  378. {
  379.   TCPSTREAM *stream = NIL;
  380.   struct hostent *host_name;
  381.   char hostname[MAILTMPLEN];
  382.   int i;
  383.   int pipei[2],pipeo[2];
  384.   /* The domain literal form is used (rather than simply the dotted decimal
  385.      as with other Unix programs) because it has to be a valid "host name"
  386.      in mailsystem terminology. */
  387.                 /* look like domain literal? */
  388.   if (host[0] == '[' && host[i = (strlen (host))-1] == ']') {
  389.     strcpy (hostname,host+1);    /* yes, copy without brackets */
  390.     hostname[i-1] = '\0';
  391.   }
  392.                 /* note that Unix requires lowercase! */
  393.   else if (host_name = gethostbyname (lcase (strcpy (hostname,host))))
  394.     strcpy (hostname,host_name->h_name);
  395.                 /* make command pipes */
  396.   if (pipe (pipei) < 0) return NIL;
  397.   if (pipe (pipeo) < 0) {
  398.     close (pipei[0]); close (pipei[1]);
  399.     return NIL;
  400.   }
  401.   if ((i = fork ()) < 0) {    /* make inferior process */
  402.     close (pipei[0]); close (pipei[1]);
  403.     close (pipeo[0]); close (pipeo[1]);
  404.     return NIL;
  405.   }
  406.   if (i) {            /* parent? */
  407.     close (pipei[1]);        /* close child's side of the pipes */
  408.     close (pipeo[0]);
  409.   }
  410.   else {            /* child */
  411.     dup2 (pipei[1],1);        /* parent's input is my output */
  412.     dup2 (pipei[1],2);        /* parent's input is my error output too */
  413.     close (pipei[0]); close (pipei[1]);
  414.     dup2 (pipeo[0],0);        /* parent's output is my input */
  415.     close (pipeo[0]); close (pipeo[1]);
  416.                 /* now run it */
  417.     execl ("/usr/ucb/rsh","rsh",hostname,"exec",service,0);
  418.     _exit (1);            /* spazzed */
  419.   }
  420.  
  421.                 /* create TCP/IP stream */
  422.   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  423.                 /* copy official host name */
  424.   stream->host = cpystr (hostname);
  425.                 /* get local name */
  426.   gethostname (hostname,MAILTMPLEN-1);
  427.   stream->localhost = cpystr ((host_name = gethostbyname (hostname)) ?
  428.                   host_name->h_name : hostname);
  429.   stream->tcpsi = pipei[0];    /* init sockets */
  430.   stream->tcpso = pipeo[1];
  431.   stream->ictr = 0;        /* init input counter */
  432.   return stream;        /* return success */
  433. }
  434.  
  435. /* TCP/IP receive line
  436.  * Accepts: TCP/IP stream
  437.  * Returns: text line string or NIL if failure
  438.  */
  439.  
  440. char *tcp_getline (stream)
  441.     TCPSTREAM *stream;
  442. {
  443.   int n,m;
  444.   char *st;
  445.   char *ret;
  446.   char *stp;
  447.   char tmp[2];
  448.   struct pollfd pollfd;
  449.   int pollstatus;
  450.   if (stream->tcpsi < 0) return NIL;
  451.   pollfd.fd = stream->tcpsi;    /* initialize selection vector */
  452.   while (stream->ictr < 1) {    /* if nothing in the buffer */
  453.                 /* block and read */
  454.     pollfd.events = POLLIN;
  455.     /* Note: am not sure here that it wouldn't also be a good idea to
  456.     restart poll() on EINTR, if SIGCHLD or whatever are expected.    DC */
  457.     while (((pollstatus = poll (&pollfd,1,-1)) < 0) && (errno == EAGAIN));
  458.     if (!pollstatus ||
  459.     ((stream->ictr = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 1)) {
  460.       close (stream->tcpsi);    /* nuke the socket */
  461.       if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
  462.       stream->tcpsi = stream->tcpso = -1;
  463.       return NIL;
  464.     }
  465.     stream->iptr = stream->ibuf;/* point at TCP buffer */
  466.   }
  467.   st = stream->iptr;        /* save start of string */
  468.   n = 0;            /* init string count */
  469.   while (stream->ictr--) {    /* look for end of line */
  470.                 /* saw the trailing CR? */
  471.     if (stream->iptr++[0] == '\015') {
  472.       ret = (char *) fs_get (n+1);
  473.       memcpy (ret,st,n);    /* copy into a free storage string */
  474.       ret[n] = '\0';        /* tie off string with null */
  475.                 /* eat the line feed */
  476.       tcp_getbuffer (stream,1,tmp);
  477.       return ret;        /* return it to caller */
  478.     }
  479.     ++n;            /* else count and try next character */
  480.   }
  481.   stp = (char *) fs_get (n);    /* copy first part of string */
  482.   memcpy (stp,st,n);
  483.                 /* recurse to get remainder */
  484.   if (st = tcp_getline (stream)) {
  485.                 /* build total string */
  486.     ret = (char *) fs_get (n+1+(m = strlen (st)));
  487.     memcpy (ret,stp,n);        /* copy first part */
  488.     memcpy (ret+n,st,m);    /* and second part */
  489.     ret[n+m] = '\0';        /* tie off string with null */
  490.     fs_give ((void **) &st);    /* flush partial string */
  491.     fs_give ((void **) &stp);    /* flush initial fragment */
  492.   }
  493.   else ret = stp;        /* return the fragment */
  494.   return ret;
  495. }
  496.  
  497. /* TCP/IP receive buffer
  498.  * Accepts: TCP/IP stream
  499.  *        size in bytes
  500.  *        buffer to read into
  501.  * Returns: T if success, NIL otherwise
  502.  */
  503.  
  504. int tcp_getbuffer (stream,size,buffer)
  505.     TCPSTREAM *stream;
  506.     unsigned long size;
  507.     char *buffer;
  508. {
  509.   unsigned long n;
  510.   char *bufptr = buffer;
  511.   struct pollfd pollfd;
  512.   int pollstatus;
  513.   pollfd.fd = stream->tcpsi;    /* initialize selection vector */
  514.   pollfd.events = POLLIN;
  515.   if (stream->tcpsi < 0) return NIL;
  516.   while (size > 0) {        /* until request satisfied */
  517.     while (stream->ictr < 1) {    /* if nothing in the buffer */
  518.       while (((pollstatus = poll (&pollfd,1,-1)) < 0) && (errno == EAGAIN));
  519.       if (!pollstatus ||
  520.       ((stream->ictr = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 1)) {
  521.     close (stream->tcpsi);    /* nuke the socket */
  522.     if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
  523.     stream->tcpsi = stream->tcpso = -1;
  524.     return NIL;
  525.       }
  526.                 /* point at TCP buffer */
  527.       stream->iptr = stream->ibuf;
  528.     }
  529.     n = min (size,stream->ictr);/* number of bytes to transfer */
  530.                 /* do the copy */
  531.     memcpy (bufptr,stream->iptr,n);
  532.     bufptr += n;        /* update pointer */
  533.     stream->iptr +=n;
  534.     size -= n;            /* update # of bytes to do */
  535.     stream->ictr -=n;
  536.   }
  537.   bufptr[0] = '\0';        /* tie off string */
  538.   return T;
  539. }
  540.  
  541. /* TCP/IP send string as record
  542.  * Accepts: TCP/IP stream
  543.  * Returns: T if success else NIL
  544.  */
  545.  
  546. int tcp_soutr (stream,string)
  547.     TCPSTREAM *stream;
  548.     char *string;
  549. {
  550.   int i;
  551.   unsigned long size = strlen (string);
  552.   struct pollfd pollfd;
  553.   int pollstatus;
  554.   pollfd.fd = stream->tcpso;    /* initialize selection vector */
  555.   pollfd.events = POLLOUT;
  556.   if (stream->tcpso < 0) return NIL;
  557.   while (size > 0) {        /* until request satisfied */
  558.     while (((pollstatus = poll (&pollfd,1,-1)) < 0) && (errno == EAGAIN));
  559.     if (!pollstatus ||
  560.     ((i = write (stream->tcpso,string,size)) < 0)) {
  561.       puts (strerror (errno));
  562.       close (stream->tcpsi);    /* nuke the socket */
  563.       if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
  564.       stream->tcpsi = stream->tcpso = -1;
  565.       return NIL;
  566.     }
  567.     size -= i;            /* count this size */
  568.     string += i;
  569.   }
  570.   return T;            /* all done */
  571. }
  572.  
  573.  
  574. /* TCP/IP close
  575.  * Accepts: TCP/IP stream
  576.  */
  577.  
  578. void tcp_close (stream)
  579.     TCPSTREAM *stream;
  580. {
  581.  
  582.   if (stream->tcpsi >= 0) {    /* no-op if no socket */
  583.     close (stream->tcpsi);    /* nuke the socket */
  584.     if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
  585.     stream->tcpsi = stream->tcpso = -1;
  586.   }
  587.                 /* flush host names */
  588.   fs_give ((void **) &stream->host);
  589.   fs_give ((void **) &stream->localhost);
  590.   fs_give ((void **) &stream);    /* flush the stream */
  591. }
  592.  
  593. /* TCP/IP get host name
  594.  * Accepts: TCP/IP stream
  595.  * Returns: host name for this stream
  596.  */
  597.  
  598. char *tcp_host (stream)
  599.     TCPSTREAM *stream;
  600. {
  601.   return stream->host;        /* return host name */
  602. }
  603.  
  604.  
  605. /* TCP/IP get local host name
  606.  * Accepts: TCP/IP stream
  607.  * Returns: local host name
  608.  */
  609.  
  610. char *tcp_localhost (stream)
  611.     TCPSTREAM *stream;
  612. {
  613.   return stream->localhost;    /* return local host name */
  614. }
  615.  
  616. /* Emulator for BSD gethostid() call
  617.  * Returns: unique identifier for this machine
  618.  */
  619.  
  620. long gethostid ()
  621. {
  622.   struct sockaddr_in sin;
  623.   int inet = t_open (TLI_TCP, O_RDWR, 0);
  624.   if (inet < 0) return 0;
  625.   getmyinaddr (inet,&sin,sizeof (sin));
  626.   close (inet);
  627.   return sin.sin_addr.s_addr;
  628. }
  629.  
  630.  
  631. /* Emulator for BSD random() call
  632.  * Returns: long random number
  633.  */
  634.  
  635. long random ()
  636. {
  637.   static int beenhere = 0;
  638.   if (!beenhere) {
  639.     beenhere = 1;
  640.     srand48 (getpid ());
  641.   }
  642.   return lrand48 ();
  643. }
  644.  
  645.  
  646. /* Copy memory block
  647.  * Accepts: destination pointer
  648.  *        source pointer
  649.  *        length
  650.  * Returns: destination pointer
  651.  */
  652.  
  653. void *memmove (s,ct,n)
  654.     void *s;
  655.     void *ct;
  656.     int n;
  657. {
  658.   char *dp, *sp;
  659.   int i;
  660.   unsigned long dest = (unsigned long) s;
  661.   unsigned long src = (unsigned long) ct;
  662.   if (((dest < src) && ((dest + n) < src)) ||
  663.       ((dest > src) && ((src + n) < dest))) return memcpy (s, ct, n);
  664.   dp = s;
  665.   sp = ct;
  666.   if (dest < src) for (i = 0; i < n; ++i) dp[i] = sp[i];
  667.   else if (dest > src) for (i = n - 1; i >= 0; --i) dp[i] = sp[i];
  668.   return s;
  669. }
  670.  
  671. /* Emulator for BSD re_comp() call
  672.  * Accepts: character string to compile
  673.  * Returns: 0 if successful, else error message
  674.  * Uses the regexpr(3X) libraries.
  675.  * Don't forget to link against /usr/lib/libgen.a
  676.  */
  677.  
  678. #define PATMAX 256
  679. static char re_space[PATMAX];
  680.  
  681. char *re_comp (str)
  682.     char *str;
  683. {
  684.   char *c;
  685.   static char *invalstr = "invalid string";
  686.   if (str) {            /* must have a string to compile */
  687.     c = compile (str,re_space,re_space + PATMAX);
  688.     if ((c >= re_space) && (c <= re_space + PATMAX)) return 0;
  689.   }
  690.   re_space[0] = 0;
  691.   return invalstr;
  692. }
  693.  
  694.  
  695. /* Emulator for BSD re_exec() call
  696.  * Accepts: string to match
  697.  * Returns: 1 if string matches, 0 if fails to match, -1 if re_comp() failed
  698.  */
  699.  
  700. long re_exec (str)
  701.     char *str;
  702. {
  703.   if (!re_space[0]) return -1;    /* re_comp() failed? */
  704.   return step (str,re_space) ? 1 : 0;
  705. }
  706.  
  707. /* Emulator for BSD scandir() call
  708.  * Accepts: directory name
  709.  *        destination pointer of names array
  710.  *        selection function
  711.  *        comparison function
  712.  * Returns: number of elements in the array or -1 if error
  713.  */
  714.  
  715. #define DIRSIZ(d) d->d_reclen
  716.  
  717. int scandir (dirname,namelist,select,compar)
  718.     char *dirname;
  719.     struct dirent ***namelist;
  720.     int (*select) ();
  721.     int (*compar) ();
  722. {
  723.   struct dirent *p,*d,**names;
  724.   int nitems;
  725.   struct stat stb;
  726.   long nlmax;
  727.   DIR *dirp = opendir (dirname);/* open directory and get status poop */
  728.   if ((!dirp) || (fstat (dirp->dd_fd,&stb) < 0)) return -1;
  729.   nlmax = stb.st_size / 24;    /* guesstimate at number of files */
  730.   names = (struct dirent **) fs_get (nlmax * sizeof (struct dirent *));
  731.   nitems = 0;            /* initially none found */
  732.   while (d = readdir (dirp)) {    /* read directory item */
  733.                 /* matches select criterion? */
  734.     if (select && !(*select) (d)) continue;
  735.                 /* get size of dirent record for this file */
  736.     p = (struct dirent *) fs_get (DIRSIZ (d));
  737.     p->d_ino = d->d_ino;    /* copy the poop */
  738.     p->d_off = d->d_off;
  739.     p->d_reclen = d->d_reclen;
  740.     strcpy (d->d_name,p->d_name);
  741.     if (++nitems >= nlmax) {    /* if out of space, try bigger guesstimate */
  742.       nlmax *= 2;        /* double it */
  743.       fs_resize ((void **) names,nlmax * sizeof (struct dirent *));
  744.     }
  745.     names[nitems - 1] = p;    /* store this file there */
  746.   }
  747.   closedir (dirp);        /* done with directory */
  748.                 /* sort if necessary */
  749.   if (nitems && compar) qsort (names,nitems,sizeof (struct dirent *),compar);
  750.   *namelist = names;        /* return directory */
  751.   return nitems;        /* and size */
  752. }
  753.  
  754. /* Emulator for BSD flock() call
  755.  * Accepts: file descriptor
  756.  *        operation bitmask
  757.  * Returns: 0 if successful, -1 if failure
  758.  * Note: this emulator does not handle shared locks
  759.  */
  760.  
  761. int flock (fd, operation)
  762.     int fd;
  763.     int operation;
  764. {
  765.   int func;
  766.                 /* translate to flock() operation */
  767.   if (operation & LOCK_UN) func = F_ULOCK;
  768.   else if (operation & (LOCK_EX|LOCK_SH))
  769.     func = (operation & LOCK_NB) ? F_TLOCK : F_LOCK;
  770.   else {
  771.     errno = EINVAL;
  772.     return -1;
  773.   }
  774.   return lockf (fd,func,0);    /* do the lockf() */
  775. }
  776.  
  777.  
  778. /* Emulator for BSD gettimeofday() call
  779.  * Accepts: address where to write timeval information
  780.  *        address where to write timezone information
  781.  * Returns: 0 if successful, -1 if failure
  782.  */
  783.  
  784. int gettimeofday (tp,tzp)
  785.     struct timeval *tp;
  786.     struct timezone *tzp;
  787. {
  788.   tp->tv_sec = time (0);    /* time since 1-Jan-70 00:00:00 GMT in secs */
  789.                 /* others aren't used in current code */
  790.   if (tzp) tzp->tz_minuteswest = tzp->tz_dsttime = 0;
  791.   tp->tv_usec = 0;
  792.   return 0;
  793. }
  794.  
  795.  
  796. /* Emulator for BSD utimes() call
  797.  * Accepts: file name
  798.  *        timeval vector for access and updated time
  799.  * Returns: 0 if successful, -1 if failure
  800.  */
  801.  
  802. int utimes (file,tvp)
  803.     char *file;
  804.     struct timeval tvp[2];
  805. {
  806.   struct utimbuf tb;
  807.   tb.actime = tvp[0].tv_sec;    /* accessed time */
  808.   tb.modtime = tvp[1].tv_sec;    /* updated time */
  809.   return utime (file,&tb);
  810. }
  811.  
  812.